<template>
  <div class="echarts-demo">
    <div class="echarts-markLine">
      <h4>echarts markLine</h4>
      <div class="echarts-wrap" ref="echartsRef"></div>
    </div>
  </div>
</template>

<script>

const seriesData = [
  {
    'value': 0.254,
    'unit': 'MPa',
    'time': 1685080221000,
  },
  {
    'value': 0.261,
    'unit': 'MPa',
    'time': 1685080332000,
  },
  {
    'value': 0.255,
    'unit': 'MPa',
    'time': 1685080371000,
  },
  {
    'value': 0.276,
    'unit': 'MPa',
    'time': 1685080632000,
  },
  {
    'value': 0.272,
    'unit': 'MPa',
    'time': 1685080671000,
  },
  {
    'value': 0.268,
    'unit': 'MPa',
    'time': 1685080779000,
  },
  {
    'value': 0.254,
    'unit': 'MPa',
    'time': 1685081082000,
  },
  {
    'value': 0.256,
    'unit': 'MPa',
    'time': 1685081118000,
  },
  {
    'value': 0.252,
    'unit': 'MPa',
    'time': 1685081421000,
  },
  {
    'value': 0.269,
    'unit': 'MPa',
    'time': 1685081529000,
  },
  {
    'value': 0.263,
    'unit': 'MPa',
    'time': 1685081571000,
  },
  {
    'value': 0.286,
    'unit': 'MPa',
    'time': 1685081682000,
  },
  {
    'value': 0.285,
    'unit': 'MPa',
    'time': 1685081832000,
  },
  {
    'value': 0.292,
    'unit': 'MPa',
    'time': 1685082171000,
  },
  {
    'value': 0.265,
    'unit': 'MPa',
    'time': 1685082321000,
  },
  {
    'value': 0.252,
    'unit': 'MPa',
    'time': 1685082429000,
  },
  {
    'value': 0.254,
    'unit': 'MPa',
    'time': 1685082471000,
  },
  {
    'value': 0.255,
    'unit': 'MPa',
    'time': 1685082582000,
  },
  {
    'value': 0.268,
    'unit': 'MPa',
    'time': 1685082921000,
  },
  {
    'value': 0.274,
    'unit': 'MPa',
    'time': 1685083032000,
  },
  {
    'value': 0.274,
    'unit': 'MPa',
    'time': 1685083068000,
  },
  {
    'value': 0.292,
    'unit': 'MPa',
    'time': 1685083179000,
  },
  {
    'value': 0.295,
    'unit': 'MPa',
    'time': 1685083332000,
  },
  {
    'value': 0.282,
    'unit': 'MPa',
    'time': 1685083671000,
  },
];

const baseSeries = [
  {
    'type': 'bar',
    'stack': 'base',
    'emphasis': {
      'disabled': true,
    },
    'barMinWidth': '100%',
    'data': [
      {
        'value': 0.23,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.23,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.23,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.23,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.23,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.23,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.225,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.228,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.228,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.228,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.228,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.228,
        'itemStyle': {
          'color': 'transparent',
        },
      },
      {
        'value': 0.228,
        'itemStyle': {
          'color': 'transparent',
        },
      },
    ],
  },
  {
    'type': 'bar',
    'stack': 'base',
    'emphasis': {
      'disabled': true,
    },
    'barMinWidth': '100%',
    'data': [
      {
        'value': 0.08199999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.08199999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.08199999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.08199999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.08199999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.08199999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07399999999999998,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07699999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07699999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07699999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07699999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07699999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
      {
        'value': 0.07699999999999999,
        'itemStyle': {
          'color': '#00acfc',
          'opacity': 0.3,
        },
      },
    ],
  },
];

const xTime = [
  '2023-05-26 13:50:21',
  '2023-05-26 13:52:12',
  '2023-05-26 13:52:51',
  '2023-05-26 13:57:12',
  '2023-05-26 13:57:51',
  '2023-05-26 13:59:39',
  '2023-05-26 14:04:42',
  '2023-05-26 14:05:18',
  '2023-05-26 14:10:21',
  '2023-05-26 14:12:09',
  '2023-05-26 14:12:51',
  '2023-05-26 14:14:42',
  '2023-05-26 14:17:12',
  '2023-05-26 14:22:51',
  '2023-05-26 14:25:21',
  '2023-05-26 14:27:09',
  '2023-05-26 14:27:51',
  '2023-05-26 14:29:42',
  '2023-05-26 14:35:21',
  '2023-05-26 14:37:12',
  '2023-05-26 14:37:48',
  '2023-05-26 14:39:39',
  '2023-05-26 14:42:12',
  '2023-05-26 14:47:51',
];

export default {
  data() {
    return {
      chart: null,
      legendSelectObj: {},
      seriesData: [],
      xTime: [],
      currentTime: '2023-05-26 14:30:00',
      markLine: {
        silent: false,
        symbol: ['none', 'none'],
        label: {
          show: true,
          color: '#00acfc',
          formatter() {
            return '预警时间';
          },
        },
        lineStyle: {
          width: 1,
          type: 'dashed',
          color: '#00acfc',
        },
        data: [
          {
            xAxis: this.$moment(this.currentTime).valueOf(),
          },
        ],
      },
    };
  },
  mounted() {
    this.xTime = xTime;
    const dataLineGL = [
      {
        name: '压力区间',
        type: 'line',
        unit: this.unit,
        showSymbol: false,
        smooth: true,
        data: seriesData,
        markPoint: {
          symbolSize: 60,
        },
      },
    ];

    this.seriesData = [...dataLineGL, ...baseSeries];
    this.drawCharts();
  },
  methods: {
    chartsPromise(option) {
      let loaded = false;
      return new Promise(resolve => {
        if (!this.$refs.echartsRef) return;
        this.chart = this.$echarts.init(this.$refs.echartsRef);
        this.chart.on('finished', () => {
          if (loaded) return;
          loaded = true;
          // 执行完成
          resolve();
        });
        this.chart.setOption(option);
      });
    },

    getTimestamp(time) {
      return this.$moment(time).valueOf();
    },

    /**
     * 获取列表中当前时间前后临近的两个元素或者与之匹配的元素
     * @param xList
     * @param currentTime
     * @return {*|*[]}
     */
    getXAxisItem(xList, currentTime) {
      const findTime = xList.find(o => o === currentTime);
      if (findTime) return findTime;
      let range = [];
      xList.forEach((item, idx) => {
        // 比较到最后一个时间元素
        if (idx === xList.length - 1 && idx - 1 > 0) {
          if (this.getTimestamp(currentTime) < this.getTimestamp(item) && this.getTimestamp(currentTime) > this.getTimestamp(xList[idx - 1])) {
            range = [
              { time: xList[idx - 1], timestamp: this.getTimestamp(xList[idx - 1]) },
              { time: item, timestamp: this.getTimestamp(item) },
            ];
          }
        } else {
          if (this.getTimestamp(currentTime) > this.getTimestamp(item) && this.getTimestamp(currentTime) < this.getTimestamp(xList[idx + 1])) {
            range = [
              { time: item, timestamp: this.getTimestamp(item) },
              { time: xList[idx + 1], timestamp: this.getTimestamp(xList[idx + 1]) },
            ];
          }
        }
      });
      return range;
    },

    /**
     * 获取markLine 标线的x轴坐标值
     */
    getMarkLineXPixel() {
      const positionTime = this.getXAxisItem(this.xTime, this.currentTime); // 计算得到位置时间或者时间范围
      let xPixel = null;
      // 直接与x轴时间列表匹配
      if (typeof positionTime === 'string' && this.$moment(positionTime).isValid()) {
        xPixel = this.chart.convertToPixel({ xAxisIndex: 0 }, positionTime);
      } else if (Array.isArray(positionTime) && positionTime.length > 0) {
        // 在时间列表范围内，但是没有与之匹配的时间值
        const firstPointPixel = this.chart.convertToPixel({ xAxisIndex: 0 }, this.xTime[0]); // 第一个点的位置
        const lastPointPixel = this.chart.convertToPixel({ xAxisIndex: 0 }, this.xTime[this.xTime.length - 1]); // 最后一个点的位置
        // 最后一个点的位置 - 第一个点的位置 = x轴的宽度
        const xWidth = lastPointPixel - firstPointPixel;
        const gapWidth = xWidth / this.xTime.length; // 每一个点间隔的宽度
        const prevPointPixel = this.chart.convertToPixel({ xAxisIndex: 0 }, positionTime[0].time);  // 前一个点的位置，单位: px
        // 当前时间值在两点之间占据的比例
        const rate = (this.getTimestamp(this.currentTime) - positionTime[0].timestamp) / (positionTime[1].timestamp - positionTime[0].timestamp);
        xPixel = rate.toFixed(4) * gapWidth + prevPointPixel;
      }
      return xPixel;
    },

    drawCharts() {
      const option = this.getOptions();

      this.chartsPromise(option).then(() => {
        const xPixel = this.getMarkLineXPixel();

        if (xPixel) {
          // 有效值百分比 * x轴的宽度 得到当前标线所属百分比的位置，由于第一个点不是整个视图宽度的起始位置，所以需要加上第一个点的位置数据，最终得到当前标线的实际位置
          option.series[0].markLine = Object.assign(this.markLine, {
            data: [
              [
                { x: xPixel, y: '80%' },
                { x: xPixel, y: '20%' },
              ],
            ],
          });
          this.chart.setOption(option);
          this.chart.resize();
        }
      });
    },

    // 销毁图表实例，避免内存溢出
    chartDispose() {
      // 销毁图表实例，避免内存溢出
      this.chart && this.chart.dispose && this.chart.dispose();
    },

    resizeChart() {
      this.chart.resize();
    },

    getOptions() {
      const option = {
        tooltip: {
          trigger: 'axis',
          backgroundColor: 'rgba(1,38,76,0.85)',
          borderColor: 'rgba(0,0,0,0.4)',
          formatter(params) {
            let htmlStr = `<div style="color:#fff;">${ params[0].axisValueLabel }</div>`;
            let lineData = '';
            //规律区间模式
            params.forEach(el => {
              if (el.componentSubType === 'line') {
                lineData += `
                <div style="display: flex; justify-content: space-between; line-height: 22px;color:#fff;width: 200px;">
                  <div>${ el.marker }<span>${ el.seriesName }</span></div>
                  <div>${ el.data.value !== null ? el.data.value + el.data.unit : '--' }</div>
                </div>`;
              }
            });
            htmlStr += lineData;
            return htmlStr;
          },
        },
        legend: {
          icon: 'rect',
          itemWidth: 12,
          itemHeight: 2,
          textStyle: {
            color: '#DCF0FF',
            rich: {
              // 选中后的文本状态
              activeName: {
                color: '#DCF0FF',
                padding: [3, 6],
                borderColor: '#00AFFC',
                borderWidth: 1,
                borderRadius: 9,
                backgroundColor: 'rgba(0,175,252,0.32)',
              },
              // 未选中的文本状态
              inactiveName: {
                color: '#DCF0FF',
                padding: [3, 6],
                borderColor: 'transparent',
                borderWidth: 1,
                backgroundColor: 'transparent',
              },
            },
          },
          lineStyle: {
            width: 2,
            type: 'solid',
          },
          right: 100,
          show: true,
          formatter: name => {
            return `{${ this.legendSelectObj[name] ? 'activeName' : 'inactiveName' }|${ name }}`;
          },
        },
        grid: {
          top: '20%',
          left: '3%',
          right: '3%',
          bottom: '10%',
          containLabel: true,
        },
        dataZoom: [
          {
            type: 'inside',
            start: 0,
            end: 100,
            color: '#000',
          },
          {
            type: 'slider',
            start: 0,
            end: 100,
            height: 8,
            bottom: 10,
            color: '#000',
            width: '80%',
            left: '10%',
            handleIcon: 'circle',
            handleStyle: {
              borderColor: '#04AFFF',
              color: '#0C6A96',
            },
            borderColor: '#04AFFF',
            fillerColor: '#04AFFF',
            textStyle: {
              color: '#fff',
              fontSize: 10,
            },
            moveHandleSize: 0,
            labelFormatter: value => {
              const timeStr = this.xTime[value];
              const time = this.$moment(timeStr).format('MM-DD HH:mm');
              return `${ time.split(' ')[0] }\n${ time.split(' ')[1] }`;
            },
          },
        ],
        xAxis: {
          type: 'category',
          data: this.xTime,
          boundaryGap: false,
          axisLabel: {
            color: '#DCF0FF',
            hideOverlap: true, //隐藏重叠的标签
            formatter: (value, index) => {
              const time = this.$moment(value).format('MM-DD HH:mm');
              return `${ time.split(' ')[0] }\n${ time.split(' ')[1] }`;
            },
          },
        },
        yAxis: [{
          type: 'value',
          scale: true,
          name: 'MPa',
          axisLabel: {
            textStyle: {
              color: '#DCF0FF',
            },
          },
          nameTextStyle: { color: '#fff' },
          splitLine: {
            lineStyle: {
              type: 'dashed',
              opacity: 0.54,
              width: 1,
            },
          },
          axisLine: {
            lineStyle: {
              color: '#8B9FB6',
              width: 1,
            },
          },
        }],
        series: this.seriesData,
      };

      return option;
    },
  },
};
</script>

<style lang="scss" scoped>
.echarts-demo {
  width: 100%;
  height: 100%;

  .echarts-markLine {
    width: 600px;
    height: 450px;
    padding: 12px;
    border: 1px solid #2c3e50;

    h4 {
      text-align: center;
    }

    .echarts-wrap {
      width: 540px;
      height: 340px;
      background: black;
    }
  }
}
</style>
